Skip to main content

Proxy:rewrite

TL;DR

next.config.js: Rewrites | Next.js

  • Redirects 不同,使用 rewrite 作為 URL 代理可以隱藏目標路徑。
  • rewrites 是一個異步函數,它預期 return 一個 array。這個 array 必須有包含 sourcedestination 屬性的 Object
  • 默認情況下,rewrites 會在檢查完 filesystem(page 和 /public 文件)之後,在動態路由產生之前被執行。但實際執行時機在 v10.1 版以後的 Next.js 可以用 beforeFilesafterFiles、和 fallback 指定。

Next.js 檢查並建立路由的順序

  1. 確認 Headers的定義
  2. 確認 rewrites 的定義
  3. 確認 beforeFiles 的定義
  4. 確認 public/_next/static 等靜態頁面的結構和定義
  5. 確認 afterFiles 的定義
    1. 如果其中有匹配的 rewrite,便會在每次匹配後檢查動態路由和靜態文件
  6. 在遇到找不到路徑、渲染 404 頁面之前,確認 fallback 的定義

語法

基本用法

module.exports = {
async rewrites() {
return [
{
source: '/about',
destination: '/',
},
]
},
}

指定 rewrite 時機寫法

module.exports = {
async rewrites() {
return {
beforeFiles: [
// These rewrites are checked after headers/redirects
// and before all files including _next/public files which
// allows overriding page files
{
source: '/some-page',
destination: '/somewhere-else',
has: [{ type: 'query', key: 'overrideMe' }],
},
],
afterFiles: [
// These rewrites are checked after pages/public files
// are checked but before dynamic routes
{
source: '/non-existent',
destination: '/somewhere-else',
},
],
fallback: [
// These rewrites are checked after both pages/public files
// and dynamic routes are checked
{
source: '/:path*',
destination: `https://my-old-site.com/:path*`,
},
],
}
},
}

參數

如果參數沒有被用在 destination 中,就會被自動以 query 的的形式傳送

module.exports = {
async rewrites() {
return [
{
source: '/old-about/:path*',
destination: '/about',
// 因為 :path 參數在 destination 中沒有被使用,所以會自動以 query 的的形式傳送
},
]
},
}

如果想要讓參數被用在 path 中,需要在 destination 中指定

module.exports = {
async rewrites() {
return [
{
source: '/docs/:path*',
destination: '/:path*',
},
]
},
}

兩個以上的參數時可能遇到參數丟失問題

當有兩個以上的參數時,就算只有一個被用在 path 中,剩餘的參數也不會被傳遞。 這時候我們需要明確指定剩餘參數的傳法:

module.exports = {
async rewrites() {
return [
{
source: '/:first/:second',
destination: '/:first?second=:second',
// 因為 :first 參數在destination 被使用,所以 :second 參數並不會被傳遞。
// 不過我們可以透過明確的指定讓參數不會丟失
},
]
},
}

路由配對

巢狀路由配對

支援巢狀路由配對

module.exports = {
async rewrites() {
return [
{
source: '/blog/:slug',
destination: '/news/:slug', // Matched parameters can be used in the destination
},
]
},
}

Wildcards

支援 Wildcards

module.exports = {
async rewrites() {
return [
{
source: '/blog/:slug*',
// 會匹配任何符合此 wildcard 的路徑,如 /blog/a/b/c/d/hello-world
destination: '/news/:slug*',
},
]
},
}

Regex

可以使用正則表達式進行路由配對

module.exports = {
async rewrites() {
return [
{
source: '/old-blog/:post(\\d{1,})',
destination: '/blog/:post',
},
]
},
}

特殊字元處理

由於(, ), {, }, :, *, +, ? 等特殊字元在正則表達式中有特殊意涵,所以如果出現在 path 中時,需要使用 \\ 作為區分

module.exports = {
async rewrites() {
return [
{
// 會匹配 `/english(default)/something`
source: '/english\\(default\\)/:slug',
destination: '/en-us/:slug',
},
]
},
}

支援 rewrite 重寫到外部 url

module.exports = {
async rewrites() {
return [
{
source: '/blog',
destination: 'https://example.com/blog',
},
{
source: '/blog/:slug',
destination: 'https://example.com/blog/:slug',
// 同樣支援外部 url 的路徑參數
},
]
},
}

Trailing Slash

如果外部 link 需要有一個 Trailing Slash,那麼

  1. 需要設定 trailingSlash: true
  2. source 中指定 path 需要加入 trailing slash
module.exports = {
trailingSlash: true, // 這裡設定
async rewrites() {
return [
{
source: '/blog/', // 需要加上 trailing slash
destination: 'https://example.com/blog/',
},
{
source: '/blog/:path*/',
destination: 'https://example.com/blog/:path*/',
},
]
},
}

Base Path

在使用轉移到外部路由時,可以指定目標路徑的 base path,並在不需要使用的路由將其關閉

module.exports = {
basePath: '/docs',

async rewrites() {
return [
{
source: '/with-basePath', // 會自動變成 /docs/with-basePath
destination: '/another', // 會自動變成 /docs/another
},
{
// 不會自動加上 base path
// 針對內部路由的 rewrite 不能使用
source: '/without-basePath',
destination: 'https://example.com',
basePath: false,
},
]
},
}

其他沒整理的內容

個人使用場景

  • config.jsapi 的代用:local 開發想打 staging 環境 api,由於 Next 不支援直接修改 api 的寫法,所以用這個 proxy 代用